package engine.individuals;

import java.util.Arrays;

public class NaturalVectorIndividual extends NaturalVector implements
		Individual<Long> {

	public NaturalVectorIndividual(long[] list) {
		super(list);
	}

	public NaturalVectorIndividual(int size) {
		super(size);
	}

	@Override
	public Long get(int index) {

		return super.getValue(index);
	}

	@Override
	public void set(int index, Long chromosome) {

		super.setValue(index, chromosome);
	}

	@Override
	public int size() {
		return super.getSize();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {

		if (this == obj) {
			return true;
		}

		if (obj == null || getClass() != obj.getClass()) {
			return false;
		}

		NaturalVectorIndividual individual = (NaturalVectorIndividual) obj;

		if (size() != individual.size()) {
			return false;
		}

		boolean isEqual = true;

		for (int i = 0; i < size() && isEqual; i++) {
			if (!get(i).equals(individual.get(i))) {
				isEqual = false;
			}
		}

		return isEqual;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		return Arrays.hashCode(super.getValues());
	}

	@Override
	public void heal() {
		for (int sec = 0; sec < size() / 4; ++sec) {
			int secEnd = (sec + 1) * 4 - 1;
			long sum = sum(sec);
			if (sum != 63L) {
				long fixValue = 63L - sum;
				long fixDiff = fixValue;
				int i = secEnd;
				while (i > sec * 4) {
					if (get(i) > 0L) {
						long p = (long) ((double) fixValue * (double) (get(i) / (double) sum));
						fixDiff -= p;
						set(i, get(i) + p);
						if (fixDiff == 0L) {
							i = sec * 4;
						}
					}
					--i;
				}
				if (fixDiff != 0L) {
					if (fixDiff > 0L) {
						i = secEnd;
						while (i > sec * 4) {
							if (get(i) + fixDiff <= 63L) {
								set(i, get(i) + fixDiff);
								i = sec * 4;
							}
							--i;
						}
					} else if (fixDiff < 0L) {
						i = secEnd;
						while (i > sec * 4) {
							if (get(i) + fixDiff >= 0L) {
								set(i, get(i) + fixDiff);
								i = sec * 4;
							}
							--i;
						}
					}
				}
				if (sum(sec) != 63L) {
					throw new IllegalStateException("Inconsistent state. Sum is: "
							+ sum(sec));
				}
			}
		}
	}

	private long sum(int sec) {
		long sum = 0L;

		for (int i = sec * 4; i < (sec + 1) * 4; ++i) {
			sum += get(i);
		}

		return sum;
	}

	public int nonZeroAlleleCount() {
		int result = 0;

		for (int i = 0; i < super.getSize(); ++i) {
			if (super.getValue(i) > 0L) {
				++result;
			}
		}

		return result;
	}
}
